package cn.zebra.dev.admin.module.security.invocation;

import cn.zebra.dev.base.module.menu.entity.BaseMenu;
import cn.zebra.dev.base.module.menu.service.BaseMenuService;
import cn.zebra.dev.base.module.role.entity.BaseRoleMenu;
import cn.zebra.dev.base.module.role.service.BaseRoleMenuService;
import cn.zebra.dev.common.constant.SysConstant;
import cn.zebra.dev.common.utils.StrUtils;
import cn.zebra.dev.config.spring.context.SpringContextUtils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @author runnable@sina.cn
 */
@Slf4j
@Component
public class AdminFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private BaseMenuService<BaseMenu> menuService;

    private BaseRoleMenuService<BaseRoleMenu> roleMenuService;

    /**
     * 所有菜单
     */
    private List<BaseMenu> menuList = new ArrayList<>();

    private final StringRedisTemplate redisTemplate;

    public AdminFilterInvocationSecurityMetadataSource(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        init();
        // 获取当前请求url
        String requestUrl = ((FilterInvocation) object).getRequestUrl().split("\\?")[0];
        String uri = requestUrl.substring(1);
        List<ConfigAttribute> configAttributes = new ArrayList<>();
        menuList.stream().filter(menu -> menu.getUrl().equals(uri)).forEach(menu -> {
            List<BaseRoleMenu> roleMenuList = roleMenuService.findListByMenuId(menu.getId());
            if (!CollectionUtils.isEmpty(roleMenuList)) {
                Long roleId = roleMenuList.get(0).getRoleId();
                configAttributes.add((ConfigAttribute) roleId::toString);
            }
        });
        if (configAttributes.size() == 0) {
            log.warn("当前访问url[{}]未配置菜单权限!", uri);
        }
        return configAttributes;
    }

    private void init() {
        if (menuService == null) {
            menuService = SpringContextUtils.getBean(BaseMenuService.class);
        }
        if (roleMenuService == null) {
            roleMenuService = SpringContextUtils.getBean(BaseRoleMenuService.class);
        }
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        String json = valueOperations.get(SysConstant.CACHE_MENU);
        if (StrUtils.isNotBlank(json)) {
            this.menuList = JSON.parseArray(json, BaseMenu.class);
        } else {
            menuList = menuService.findList();
            valueOperations.set(SysConstant.CACHE_MENU, JSON.toJSONString(menuList));
        }
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return FilterInvocation.class.isAssignableFrom(aClass);
    }
}
